鐵人賽至今也過半了,所以為了慶祝一下,我們最後來講講各種 Vue App 之間的溝通方法。扣除掉你可能是使用 Webpack 來封裝你的 App 之外,我們也會提及在不同的封裝之間,我們的 App 要如何來進行溝通。
我們之前有提過 new Vue
之間的一些狀況,
當我們在同一個封裝過程中,這兩個 App 其實還是分屬於不同的執行個體。所以,兩個不同的 App 之間,我們原本可以使用的一些事件溝通方式,在這邊當然就無法使用。所以,根據 上一篇 所提及的 EventBus 的方法,我們可以在外部先製作一個 EventBus 來進行溝通。
import Vue from 'vue'
import App1 from './App1.vue'
import App2 from './App2.vue'
import EventBus from '@/extends/OldDriver.js'
new Vue({
created () {
EventBus.$on('App1Created', () => {
// App 1 建立囉~
})
},
render: h => h(App1)
}).$mount('#app1')
new Vue({
created () {
EventBus.$on('App2Created', () => {
// App 2 建立囉~
})
},
render: h => h(App2)
}).$mount("#app2')
這麼一來,你在其他的元件內部,只要一樣使用 EventBus 就能跨出 App 來做事件傳遞。這個先決條件就是,你的整套應用程式,必須要在 同一個 Webpack 的封裝下,才能正常運作。
當然,如果你想要使用 Vuex 來做資料傳遞,只要兩個 App 都使用同一套 Store 的話,這麼做也是可行的。
import Vue from 'vue'
import App1 from './App1.vue'
import App2 from './App2.vue'
import Store from './stores'
new Vue({
Store,
render: h => h(App1)
}).$mount('#app1')
new Vue({
Store,
render: h => h(App2)
}).$mount("#app2')
這麼一來,你的兩個 App 就能共用同一組狀態管理器,當然,跟事件傳遞一樣,你必須自己釐清各種觸發狀態以及資料更新的時機,還有關於生命週期的事情。
所以,上述的方法都還算是能夠解決各種溝通的面向。但是,會不會有失靈的時候?撇除掉你使用 Vuex 來做資料交換,事件傳遞是不是真的使用 EventBus 就是萬解呢?
上一個段落提及了 同一個 Webpack 的封裝下,才能正常運作。那麼,為何會有 EventBus 失靈的狀況?是有的,在你不使用 Webpack,爾或者是你使用不同的 Webpack 程序來封裝的時候。關於使用不同的封裝,我們後續在動態載入的時候會再詳細提及,這裡先知道有這件事情就好。
所謂的不同封裝,你可以想像成有兩個 Vue App,但是他跑在兩個不同的應用程序結構下。所以,你以為的 new Vue()
就不會是同一件事情。所以,即便他們看起來都叫做 EventBus,但是在封裝過後,兩個不同的 App 所封裝出來的 EventBus 就會分處於不同的應用範圍( scope )中,所以,這兩個 EventBus 不會互通有無也是很合理的。
import Vue from 'vue'
import App1 from './app1/App.vue'
import EventBus from '@/app1/extends/OldDriver.js'
new Vue({
created () {
EventBus.$on('App1Created', () => {
// App 1 建立囉~
})
},
render: h => h(App1)
}).$mount('#app1')
import Vue from 'vue'
import App2 from './app2/App.vue'
import EventBus from '@/app2/extends/OldDriver.js'
new Vue({
created () {
EventBus.$on('App2Created', () => {
// App 2 建立囉~
})
},
render: h => h(App2)
}).$mount('#app2')
你覺得上面兩個 App 所使用的 EventBus 會是同一台車嗎?這種狀況,即便你使用 Vuex 也是兩套 不一樣 的狀態管理器,亦即,你的 Store 不是我的 Store,所以就算是這樣,你還是無法共用。
在這種情況下,我們該怎麼把事件傳遞處理的 比較好 呢?另外一種處理思維是,我們將這個是件傳遞的工具,往上交給 window
來做,亦即:
window.EventBus = new Vue()
這麼一來,無論我是否使用相同的 Webpack 封裝,我只要使用 window.EventBus
就能夠 上同一台車 呼叫到我所指定過的事件,也能互相傳遞資訊了。
同樣的情況,你也可以把 Vuex 往上提升到最外層( window )。換句話說,即便你分開封裝兩套 App,只要 Vuex 都能正確引入,那麼你還是可以使用同一套狀態管理器來操作的。
import Vue from 'vue'
import App1 from './app1/App.vue'
new Vue({
window.Store,
render: h => h(App1)
}).$mount('#app1')
import Vue from 'vue'
import App2 from './app2/App.vue'
new Vue({
window.Store,
render: h => h(App2)
}).$mount('#app2')
只是這樣會增加應用程式的複雜度,而且絕大多數的應用情境裡,可能也不會這樣操作。但是背骨如我,我們後續在動態載入的時候會告訴你這種奇怪的操作方式。
不好但是可以接受(結案)。
你必須意識到一件事情,所謂的 window
是指什麼?
Chrome DevTool 是一個好東西, 每個人都應該要有。
你必須清楚知道這樣做的風險是什麼,不然是相當不建議這樣操作的。或許我後面在動態載入的時候會提及 window
這件事情,不過,對於事件傳遞,甚至是狀態控制這些事項,倘若你有較為敏感的資訊,例如登入的使用者資料,那麼就非常不建議使用這種方式。
除非,你的系統是公司內部使用,然後內部控管做得非常好。
不然就是 App 做好了不要上線(選我正解)。
當然,為了安全性,你也可以使用一些簡單的查核機制,來確保你的事件傳播以及狀態控制器被 呼叫 的合法性。不過這件事情真的就是只能防君子,不防小人。畢竟你知道的,即便你的 JavaScript 已經壓縮過了,我們還是可以找到你想要做的那些事情( 不要問,很可怕 )。
這個章節真的比較畸形,其實你不太會有機會分開打包你的 App,但你知道的,我就是會做這種事情的人。不然鐵人賽就沒什麼特別的東西可以寫了啊(燦笑)。